home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MacHacksBug / Python 1.5.2c1 / Mac / Lib / lib-toolbox / aepack.py < prev    next >
Encoding:
Python Source  |  2000-06-23  |  9.3 KB  |  347 lines

  1. """Tools for use in AppleEvent clients and servers:
  2. conversion between AE types and python types
  3.  
  4. pack(x) converts a Python object to an AEDesc object
  5. unpack(desc) does the reverse
  6. coerce(x, wanted_sample) coerces a python object to another python object
  7. """
  8.  
  9. #
  10. # This code was originally written by Guido, and modified/extended by Jack
  11. # to include the various types that were missing. The reference used is
  12. # Apple Event Registry, chapter 9.
  13. #
  14.  
  15. import struct
  16. import string
  17. import types
  18. from string import strip
  19. from types import *
  20. import AE
  21. from AppleEvents import *
  22. from AERegistry import *
  23. from AEObjects import *
  24. import MacOS
  25. import macfs
  26. import StringIO
  27. import aetypes
  28. from aetypes import mkenum, mktype
  29.  
  30. # These ones seem to be missing from AppleEvents
  31. # (they're in AERegistry.h)
  32.  
  33. #typeColorTable = 'clrt'
  34. #typeDrawingArea = 'cdrw'
  35. #typePixelMap = 'cpix'
  36. #typePixelMapMinus = 'tpmm'
  37. #typeRotation = 'trot'
  38. #typeTextStyles = 'tsty'
  39. #typeStyledText = 'STXT'
  40. #typeAEText = 'tTXT'
  41. #typeEnumeration = 'enum'
  42.  
  43. #
  44. # Some AE types are immedeately coerced into something
  45. # we like better (and which is equivalent)
  46. #
  47. unpacker_coercions = {
  48.     typeComp : typeFloat,
  49.     typeColorTable : typeAEList,
  50.     typeDrawingArea : typeAERecord,
  51.     typeFixed : typeFloat,
  52.     typeExtended : typeFloat,
  53.     typePixelMap : typeAERecord,
  54.     typeRotation : typeAERecord,
  55.     typeStyledText : typeAERecord,
  56.     typeTextStyles : typeAERecord,
  57. };
  58.  
  59. #
  60. # Some python types we need in the packer:
  61. #
  62. AEDescType = type(AE.AECreateDesc('TEXT', ''))
  63. _sample_fss = macfs.FSSpec(':')
  64. _sample_alias = _sample_fss.NewAliasMinimal()
  65. FSSType = type(_sample_fss)
  66. AliasType = type(_sample_alias)
  67.  
  68. def pack(x, forcetype = None):
  69.     """Pack a python object into an AE descriptor"""
  70.     
  71.     if forcetype:
  72.         if type(x) is StringType:
  73.             return AE.AECreateDesc(forcetype, x)
  74.         else:
  75.             return pack(x).AECoerceDesc(forcetype)
  76.             
  77.     if x == None:
  78.         return AE.AECreateDesc('null', '')
  79.         
  80.     t = type(x)
  81.     if t == AEDescType:
  82.         return x
  83.     if t == FSSType:
  84.         return AE.AECreateDesc('fss ', x.data)
  85.     if t == AliasType:
  86.         return AE.AECreateDesc('alis', x.data)
  87.     if t == IntType:
  88.         return AE.AECreateDesc('long', struct.pack('l', x))
  89.     if t == FloatType:
  90.         return AE.AECreateDesc('doub', struct.pack('d', x))
  91.     if t == StringType:
  92.         return AE.AECreateDesc('TEXT', x)
  93.     if t == ListType:
  94.         list = AE.AECreateList('', 0)
  95.         for item in x:
  96.             list.AEPutDesc(0, pack(item))
  97.         return list
  98.     if t == DictionaryType:
  99.         record = AE.AECreateList('', 1)
  100.         for key, value in x.items():
  101.             record.AEPutParamDesc(key, pack(value))
  102.         return record
  103.     if t == InstanceType and hasattr(x, '__aepack__'):
  104.         return x.__aepack__()
  105.     return AE.AECreateDesc('TEXT', repr(x)) # Copout
  106.  
  107. def unpack(desc):
  108.     """Unpack an AE descriptor to a python object"""
  109.     t = desc.type
  110.     
  111.     if unpacker_coercions.has_key(t):
  112.         desc = desc.AECoerceDesc(unpacker_coercions[t])
  113.         t = desc.type # This is a guess by Jack....
  114.     
  115.     if t == typeAEList:
  116.         l = []
  117.         for i in range(desc.AECountItems()):
  118.             keyword, item = desc.AEGetNthDesc(i+1, '****')
  119.             l.append(unpack(item))
  120.         return l
  121.     if t == typeAERecord:
  122.         d = {}
  123.         for i in range(desc.AECountItems()):
  124.             keyword, item = desc.AEGetNthDesc(i+1, '****')
  125.             d[keyword] = unpack(item)
  126.         return d
  127.     if t == typeAEText:
  128.         record = desc.AECoerceDesc('reco')
  129.         return mkaetext(unpack(record))
  130.     if t == typeAlias:
  131.         return macfs.RawAlias(desc.data)
  132.     # typeAppleEvent returned as unknown
  133.     if t == typeBoolean:
  134.         return struct.unpack('b', desc.data)[0]
  135.     if t == typeChar:
  136.         return desc.data
  137.     # typeColorTable coerced to typeAEList
  138.     # typeComp coerced to extended
  139.     # typeData returned as unknown
  140.     # typeDrawingArea coerced to typeAERecord
  141.     if t == typeEnumeration:
  142.         return mkenum(desc.data)
  143.     # typeEPS returned as unknown
  144.     if t == typeFalse:
  145.         return 0
  146.     if t == typeFloat:
  147.         data = desc.data
  148.         return struct.unpack('d', data)[0]
  149.     if t == typeFSS:
  150.         return macfs.RawFSSpec(desc.data)
  151.     if t == typeInsertionLoc:
  152.         record = desc.AECoerceDesc('reco')
  153.         return mkinsertionloc(unpack(record))
  154.     # typeInteger equal to typeLongInteger
  155.     if t == typeIntlText:
  156.         script, language = struct.unpack('hh', desc.data[:4])
  157.         return aetypes.IntlText(script, language, desc.data[4:])
  158.     if t == typeIntlWritingCode:
  159.         script, language = struct.unpack('hh', desc.data)
  160.         return aetypes.IntlWritingCode(script, language)
  161.     if t == typeKeyword:
  162.         return mkkeyword(desc.data)
  163.     if t == typeLongInteger:
  164.         return struct.unpack('l', desc.data)[0]
  165.     if t == typeNull:
  166.         return None
  167.     if t == typeMagnitude:
  168.         v = struct.unpack('l', desc.data)
  169.         if v < 0:
  170.             v = 0x100000000L + v
  171.         return v
  172.     if t == typeObjectSpecifier:
  173.         record = desc.AECoerceDesc('reco')
  174.         return mkobject(unpack(record))
  175.     # typePict returned as unknown
  176.     # typePixelMap coerced to typeAERecord
  177.     # typePixelMapMinus returned as unknown
  178.     # typeProcessSerialNumber returned as unknown
  179.     if t == typeQDPoint:
  180.         v, h = struct.unpack('hh', desc.data)
  181.         return aetypes.QDPoint(v, h)
  182.     if t == typeQDRectangle:
  183.         v0, h0, v1, h1 = struct.unpack('hhhh', desc.data)
  184.         return aetypes.QDRectangle(v0, h0, v1, h1)
  185.     if t == typeRGBColor:
  186.         r, g, b = struct.unpack('hhh', desc.data)
  187.         return aetypes.RGBColor(r, g, b)
  188.     # typeRotation coerced to typeAERecord
  189.     # typeScrapStyles returned as unknown
  190.     # typeSessionID returned as unknown
  191.     if t == typeShortFloat:
  192.         return struct.unpack('f', desc.data)[0]
  193.     if t == typeShortInteger:
  194.         return struct.unpack('h', desc.data)[0]
  195.     # typeSMFloat identical to typeShortFloat
  196.     # typeSMInt    indetical to typeShortInt
  197.     # typeStyledText coerced to typeAERecord
  198.     if t == typeTargetID:
  199.         return mktargetid(desc.data)
  200.     # typeTextStyles coerced to typeAERecord
  201.     # typeTIFF returned as unknown
  202.     if t == typeTrue:
  203.         return 1
  204.     if t == typeType:
  205.         return mktype(desc.data)
  206.     #
  207.     # The following are special
  208.     #
  209.     if t == 'rang':
  210.         record = desc.AECoerceDesc('reco')
  211.         return mkrange(unpack(record))
  212.     if t == 'cmpd':
  213.         record = desc.AECoerceDesc('reco')
  214.         return mkcomparison(unpack(record))
  215.     if t == 'logi':
  216.         record = desc.AECoerceDesc('reco')
  217.         return mklogical(unpack(record))
  218.     return mkunknown(desc.type, desc.data)
  219.     
  220. def coerce(data, egdata):
  221.     """Coerce a python object to another type using the AE coercers"""
  222.     pdata = pack(data)
  223.     pegdata = pack(egdata)
  224.     pdata = pdata.AECoerceDesc(pegdata.type)
  225.     return unpack(pdata)
  226.  
  227. #
  228. # Helper routines for unpack
  229. #
  230. def mktargetid(data):
  231.     sessionID = getlong(data[:4])
  232.     name = mkppcportrec(data[4:4+72])
  233.     location = mklocationnamerec(data[76:76+36])
  234.     rcvrName = mkppcportrec(data[112:112+72])
  235.     return sessionID, name, location, rcvrName
  236.  
  237. def mkppcportrec(rec):
  238.     namescript = getword(rec[:2])
  239.     name = getpstr(rec[2:2+33])
  240.     portkind = getword(rec[36:38])
  241.     if portkind == 1:
  242.         ctor = rec[38:42]
  243.         type = rec[42:46]
  244.         identity = (ctor, type)
  245.     else:
  246.         identity = getpstr(rec[38:38+33])
  247.     return namescript, name, portkind, identity
  248.  
  249. def mklocationnamerec(rec):
  250.     kind = getword(rec[:2])
  251.     stuff = rec[2:]
  252.     if kind == 0: stuff = None
  253.     if kind == 2: stuff = getpstr(stuff)
  254.     return kind, stuff
  255.  
  256. def mkunknown(type, data):
  257.     return aetypes.Unknown(type, data)
  258.  
  259. def getpstr(s):
  260.     return s[1:1+ord(s[0])]
  261.  
  262. def getlong(s):
  263.     return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
  264.  
  265. def getword(s):
  266.     return (ord(s[0])<<8) | (ord(s[1])<<0)
  267.  
  268. def mkkeyword(keyword):
  269.     return aetypes.Keyword(keyword)
  270.  
  271. def mkrange(dict):
  272.     return aetypes.Range(dict['star'], dict['stop'])
  273.  
  274. def mkcomparison(dict):
  275.     return aetypes.Comparison(dict['obj1'], dict['relo'].enum, dict['obj2'])
  276.  
  277. def mklogical(dict):
  278.     return aetypes.Logical(dict['logc'], dict['term'])
  279.  
  280. def mkstyledtext(dict):
  281.     return aetypes.StyledText(dict['ksty'], dict['ktxt'])
  282.     
  283. def mkaetext(dict):
  284.     return aetypes.AEText(dict[keyAEScriptTag], dict[keyAEStyles], dict[keyAEText])
  285.     
  286. def mkinsertionloc(dict):
  287.     return aetypes.InsertionLoc(dict[keyAEObject], dict[keyAEPosition])
  288.  
  289. def mkobject(dict):
  290.     want = dict['want'].type
  291.     form = dict['form'].enum
  292.     seld = dict['seld']
  293.     fr   = dict['from']
  294.     if form in ('name', 'indx', 'rang', 'test'):
  295.         if want == 'text': return aetypes.Text(seld, fr)
  296.         if want == 'cha ': return aetypes.Character(seld, fr)
  297.         if want == 'cwor': return aetypes.Word(seld, fr)
  298.         if want == 'clin': return aetypes.Line(seld, fr)
  299.         if want == 'cpar': return aetypes.Paragraph(seld, fr)
  300.         if want == 'cwin': return aetypes.Window(seld, fr)
  301.         if want == 'docu': return aetypes.Document(seld, fr)
  302.         if want == 'file': return aetypes.File(seld, fr)
  303.         if want == 'cins': return aetypes.InsertionPoint(seld, fr)
  304.     if want == 'prop' and form == 'prop' and aetypes.IsType(seld):
  305.         return aetypes.Property(seld.type, fr)
  306.     return aetypes.ObjectSpecifier(want, form, seld, fr)
  307.  
  308. def _test():
  309.     """Test program. Pack and unpack various things"""
  310.     objs = [
  311.         'a string',
  312.         12,
  313.         12.0,
  314.         None,
  315.         ['a', 'list', 'of', 'strings'],
  316.         {'key1': 'value1', 'key2':'value2'},
  317.         macfs.FSSpec(':'),
  318.         macfs.FSSpec(':').NewAliasMinimal(),
  319.         aetypes.Enum('enum'),
  320.         aetypes.Type('type'),
  321.         aetypes.Keyword('kwrd'),
  322.         aetypes.Range(1, 10),
  323.         aetypes.Comparison(1, '<   ', 10),
  324.         aetypes.Logical('not ', 1),
  325.         # Cannot do StyledText
  326.         # Cannot do AEText
  327.         aetypes.IntlText(0, 0, 'international text'),
  328.         aetypes.IntlWritingCode(0,0),
  329.         aetypes.QDPoint(50,100),
  330.         aetypes.QDRectangle(50,100,150,200),
  331.         aetypes.RGBColor(0x7000, 0x6000, 0x5000),
  332.         aetypes.Unknown('xxxx', 'unknown type data'),
  333.         aetypes.Character(1),
  334.         aetypes.Character(2, aetypes.Line(2)),
  335.     ]
  336.     for o in objs:
  337.         print 'BEFORE', o, `o`
  338.         packed = pack(o)
  339.         unpacked = unpack(packed)
  340.         print 'AFTER ', unpacked, `unpacked`
  341.     import sys
  342.     sys.exit(1)
  343.     
  344. if __name__ == '__main__':
  345.     _test()
  346.     
  347.